// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com

// ReSharper disable CheckNamespace
// ReSharper disable CommentTypo
// ReSharper disable IdentifierTypo
// ReSharper disable InconsistentNaming
// ReSharper disable UnusedMember.Global

/* CodeOmr.cs --
 * Ars Magna project, http://arsmagna.ru
 */

#nullable enable

namespace PdfSharpCore.Drawing.BarCodes;

/// <summary>
/// Represents an OMR code.
/// </summary>
public class CodeOmr
    : BarCode
{
    #region Properties

    /// <summary>
    /// Gets or sets a value indicating whether a synchronize mark is rendered.
    /// </summary>
    public bool SynchronizeCode { get; set; }

    /// <summary>
    /// Gets or sets the distance of the markers.
    /// </summary>
    public double MakerDistance { get; set; } = 12;

    /// <summary>
    /// Gets or sets the thickness of the makers.
    /// </summary>
    public double MakerThickness { get; set; } = 1;

    #endregion

    #region Construction

    /// <summary>
    /// Конструктор.
    /// </summary>
    public CodeOmr
        (
            string text,
            XSize size,
            CodeDirection direction
        )
        : base (text, size, direction)
    {
        // пустое тело конструктора
    }

    #endregion

    #region BarCode members

    /// <inheritdoc cref="BarCode.Render"/>
    protected internal override void Render
        (
            XGraphics graphics,
            XBrush brush,
            XFont font,
            XPoint position
        )
    {
        var state = graphics.Save();

        switch (Direction)
        {
            case CodeDirection.RightToLeft:
                graphics.RotateAtTransform (180, position);
                break;

            case CodeDirection.TopToBottom:
                graphics.RotateAtTransform (90, position);
                break;

            case CodeDirection.BottomToTop:
                graphics.RotateAtTransform (-90, position);
                break;
        }

        //XPoint pt = center - size / 2;
        var pt = position - CalcDistance (AnchorType.TopLeft, Anchor, Size);
        uint.TryParse (Text, out var value);

        // HACK: Project Wallenwein: set LK
        value |= 1;
        SynchronizeCode = true;

        if (SynchronizeCode)
        {
            var rect = new XRect (pt.X, pt.Y, MakerThickness, Size.Height);
            graphics.DrawRectangle (brush, rect);
            pt.X += 2 * MakerDistance;
        }

        for (var idx = 0; idx < 32; idx++)
        {
            if ((value & 1) == 1)
            {
                var rect = new XRect (pt.X + idx * MakerDistance, pt.Y, MakerThickness, Size.Height);
                graphics.DrawRectangle (brush, rect);
            }

            value = value >> 1;
        }

        graphics.Restore (state);
    }

    ///// <summary>
    ///// Renders the mark at the given position.
    ///// </summary>
    ///// <param name="position">The mark position to render.</param>
    //private void RenderMark(int position)
    //{
    //  double yPos =  TopLeft.Y + UpperDistance + position * ToUnit(markDistance).Centimeter;
    //  //Center mark
    //  double xPos = TopLeft.X + Width / 2 - this.MarkWidth / 2;

    //  Gfx.DrawLine(pen, xPos, yPos, xPos + MarkWidth, yPos);
    //}

    ///// <summary>
    ///// Distance of the marks. Default is 2/6 inch.
    ///// </summary>
    //public MarkDistance MarkDistance
    //{
    //  get { return markDistance; }
    //  set { markDistance = value; }
    //}
    //private MarkDistance markDistance = MarkDistance.Inch2_6;

    ///// <summary>
    ///// Converts a mark distance to an XUnit object.
    ///// </summary>
    ///// <param name="markDistance">The mark distance to convert.</param>
    ///// <returns>The converted mark distance.</returns>
    //public static XUnit ToUnit(MarkDistance markDistance)
    //{
    //  switch (markDistance)
    //  {
    //    case MarkDistance.Inch1_6:
    //      return XUnit.FromInch(1.0 / 6.0);
    //    case MarkDistance.Inch2_6:
    //      return XUnit.FromInch(2.0 / 6.0);
    //    case MarkDistance.Inch2_8:
    //      return XUnit.FromInch(2.0 / 8.0);
    //    default:
    //      throw new ArgumentOutOfRangeException("markDistance");
    //  }
    //}

    ///// <summary>
    ///// The upper left point of the reading zone.
    ///// </summary>
    //public XPoint TopLeft
    //{
    //  get
    //  {
    //    XPoint topLeft = center;
    //    topLeft.X -= Width;
    //    double height = upperDistance + lowerDistance;
    //    height += (data.Marks.Length - 1) * ToUnit(MarkDistance).Centimeter;
    //    topLeft.Y -= height / 2;
    //    return topLeft;
    //  }
    //}

    ///// <summary>
    ///// the upper distance from position to the first mark.
    ///// The default value is 8 / 6 inch.
    ///// </summary>
    //double UpperDistance
    //{
    //  get { return upperDistance; }
    //  set { upperDistance = value; }
    //}
    //private double upperDistance = XUnit.FromInch(8.0 / 6.0).Centimeter;

    ///// <summary>
    ///// The lower distance from the last possible mark to the end of the reading zone.
    ///// The default value is
    ///// </summary>
    //double LowerDistance
    //{
    //  get { return lowerDistance; }
    //  set { lowerDistance = value; }
    //}
    //private double lowerDistance = XUnit.FromInch(2.0 / 6.0).Centimeter;

    ///// <summary>
    ///// Gets or sets the width of the reading zone.
    ///// Default and minimum is 3/12 inch.
    ///// </summary>
    //public double Width
    //{
    //  get { return width; }
    //  set { width = value; }
    //}
    //double width = XUnit.FromInch(3.0 / 12.0).Centimeter;

    ///// <summary>
    ///// Gets or sets the mark width. Default is 1/2 * width.
    ///// </summary>
    //public XUnit MarkWidth
    //{
    //  get
    //  {
    //    if (markWidth > 0)
    //      return markWidth;
    //    else
    //      return width / 2;
    //  }
    //  set { markWidth = value; }
    //}
    //XUnit markWidth;

    ///// <summary>
    ///// Gets or sets the width of the mark line. Default is 1pt.
    ///// </summary>
    //public XUnit MarkLineWidth
    //{
    //  get { return markLineWidth; }
    //  set { markLineWidth = value; }
    //}
    //XUnit markLineWidth = 1;

    /// <inheritdoc cref="CodeBase.CheckCode"/>
    protected override void CheckCode
        (
            string text
        )
    {
        // пустое тело метода
    }

    #endregion
}
